﻿using System.Collections.Generic;
using UnityEngine;

/// <summary>马路圆角</summary>
public class RoadCircularBead : MonoBehaviour
{
    public MeshFilter meshFilter;
    public MeshRenderer m_renderer;
    public Material material;
    private List<Transform> P = new List<Transform>();
    void Start()
    {
        List<Vector3> Points = new List<Vector3>();
        for (int i = 0; i < transform.childCount; i++)
        {
            if (transform.GetChild(i).gameObject.activeSelf)
            {
                P.Add(transform.GetChild(i));
                Points.Add(transform.GetChild(i).localPosition);
            }
        }

        meshFilter.mesh = CreateRoad(Points.ToArray(), 4f);
        m_renderer.material = material;

    }
    public GameObject temp;
    /// <summary>顶点</summary>
    public List<Vector3> l_vertesx;
    public List<int> l_triangles;

    public float uvi = 0;

    List<Vector2> l_uv = new List<Vector2>();
    #region 创建路径
    Mesh CreateRoad(Vector3[] trans, float width)
    {
        #region 顶点
        l_vertesx = new List<Vector3>();
        //第一个点
        Vector3 fa = GetPointsOnParalleLines(trans[0], trans[1], -width / 2, trans[0]);
        Vector3 fd = GetPointsOnParalleLines(trans[0], trans[1], width / 2, trans[0]);

        AddList(l_vertesx, fa, fd);
        AddList(l_uv, Vector2.zero, Vector2.up);
        ST(temp, P[trans.Length - 1], new string[] { "0fa00", "1fd01" }, fa, fd);

        Vector3 lastR = fa;
        Vector3 lastL = fd;

        for (int i = 1; i < trans.Length - 1; i++)       //中间的点
        {
            Vector3 A = trans[i - 1];//上一节点
            Vector3 B = trans[i];//当前节点
            Vector3 C = trans[i + 1];//下一节点
            uvi = Vector3.Distance(A, B);
            #region abcd(本节点与上一节点的四边形)-opmn(本节点与下一节点的四边形)
            Vector3 a = GetPointsOnParalleLines(A, B, -width / 2, A);
            Vector3 b = GetPointsOnParalleLines(A, B, -width / 2, B);
            Vector3 c = GetPointsOnParalleLines(A, B, width / 2, B);
            Vector3 d = GetPointsOnParalleLines(A, B, width / 2, A);

            Vector3 o = GetPointsOnParalleLines(C, B, -width / 2, C);
            Vector3 p = GetPointsOnParalleLines(C, B, -width / 2, B);
            Vector3 m = GetPointsOnParalleLines(C, B, width / 2, B);
            Vector3 n = GetPointsOnParalleLines(C, B, width / 2, C);

            //两个向量的外积
            Vector3 crossRes = Vector3.Cross(B - A, C - B);
            if (crossRes.y < 0)//左拐
            {
                Debug.Log("左");
                Vector3 k = (GetLinesIntersection(a, b, m, n) - B).normalized * width / 2 + B; ;
                Vector3 l = GetLinesIntersection(c, d, o, p);
                Vector3 e = GetPointsOnParalleLines(d, l, -width, l);
                Vector3 r = GetPointsOnParalleLines(o, l, width, l);
                float ll = Vector3.Distance(lastL, l);
                float Bel = Vector3.Distance(A, B);
                float ek = Vector3.Distance(k, e);
                float kr = Vector3.Distance(k, r);
                float bk = Vector3.Distance(b, k);
                float km = Vector3.Distance(k, m);
                float mr = Vector3.Distance(m, r);

                Vector2 uve = new Vector2(ll / width, 0);
                Vector2 uvl = new Vector2(ll / width, 1);
                Vector2 uvb = new Vector2(Bel / width, 0);
                Vector2 uvB = new Vector2(Bel / width, 0.5f);
                Vector2 uvk = new Vector2((Bel + bk) / width, 0);
                Vector2 uvm = new Vector2((Bel + bk + km) / width, 0);
                Vector2 uvr = new Vector2((Bel + bk + km + mr) / width, 0);
                //Vector2 uvl = new Vector2((Bel + bk + km + mr) / width, 1);

                AddList(l_vertesx, B, e, l);//2 3 4
                AddList(l_uv, uvB, uve, uvl);
                ST(temp, P[i], new string[] { "2B", "3e", "4l" }, B, e, l);

                AddList(l_vertesx, B, b, e);//5 6 7
                AddList(l_uv, uvB, uvb, uve);
                ST(temp, P[i], new string[] { "5B", "6b", "7e" }, B, b, e);

                AddList(l_vertesx, B, k, b);//8 9 10
                AddList(l_uv, new Vector2((Bel + bk / 2) / width, 0.5f), uvk, uvb);
                ST(temp, P[i], new string[] { "8B", "9k", "10b" }, B, k, b);

                AddList(l_vertesx, B, m, k);//11 12 13 
                AddList(l_uv, new Vector2((Bel + bk + km / 2) / width, 0.5f), uvm, uvk);
                ST(temp, P[i], new string[] { "11B", "12m", "13k" }, B, m, k);

                AddList(l_vertesx, B, r, m);//14 15 16
                AddList(l_uv, new Vector2((Bel + bk + km) / width, 0.5f), uvr, uvm);
                ST(temp, P[i], new string[] { "14B", "15r", "16m" }, B, r, m);

                AddList(l_vertesx, B, l, r);//17 18 19
                AddList(l_uv, new Vector2((Bel + bk + km) / width, 0.5f), new Vector2((Bel + bk + km + mr) / width, 1), uvr);
                ST(temp, P[i], new string[] { "17B", "18l", "19r" }, B, l, r);

                #region  uv

                //l_uv.Add(new Vector2((uvi + ek + ll + kr) / width, 1));//5 l
                //l_uv.Add(new Vector2((uvi + ek + ll + kr) / width, 0));//6 r
                //l_uv.Add(new Vector2((uvi + ek + ll) / width, 0));//7 k

                uvi = uvi + (bk + km + mr);

                lastL = l;
                lastR = r;
                #endregion
            }
            else//右拐
            {
                Debug.Log("右");
                Vector3 k = (GetLinesIntersection(c, d, o, p) - B).normalized * width / 2 + B;
                Vector3 l = GetLinesIntersection(a, b, m, n);
                Vector3 e = GetPointsOnParalleLines(a, l, width, l);
                Vector3 r = GetPointsOnParalleLines(n, l, -width, l);

                AddList(l_vertesx, B, l, e);//2 3 4
                ST(temp, P[i], new string[] { "2B", "3l", "4e" }, B, l, e);
                AddList(l_vertesx, B, e, c);//5 6 7
                ST(temp, P[i], new string[] { "5B", "6e", "7c" }, B, e, c);
                AddList(l_vertesx, B, c, k);//8 9 10
                ST(temp, P[i], new string[] { "8B", "9c", "10k" }, B, c, k);
                AddList(l_vertesx, B, k, p);//11 12 13 
                ST(temp, P[i], new string[] { "11B", "12k", "13p" }, B, k, p);
                AddList(l_vertesx, B, p, r);//14 15 16
                ST(temp, P[i], new string[] { "14B", "15p", "16r" }, B, p, r);
                AddList(l_vertesx, B, r, l);//17 18 19
                ST(temp, P[i], new string[] { "17B", "18r", "19l" }, B, r, l);

                lastL = r;
                lastR = l;

                #region uv

                float ll = Vector3.Distance(lastR, l);
                float ek = Vector3.Distance(k, e);
                float kr = Vector3.Distance(k, r);

                l_uv.Add(new Vector2((uvi + ll) / width, 0));
                l_uv.Add(new Vector2((uvi + ll) / width, 1));
                l_uv.Add(new Vector2((uvi + ek + ll) / width, 1));

                l_uv.Add(new Vector2((uvi + ek + ll + kr) / width, 1));
                l_uv.Add(new Vector2((uvi + ek + ll + kr) / width, 0));
                l_uv.Add(new Vector2((uvi + ek + ll) / width, 1));

                //uvi = uvi + (ek + ll + kr);
                //lastR = l;
                //lastL = e;
                #endregion
            }
            #endregion
        }
        #region 最后一个点

        Vector3 lb = GetPointsOnParalleLines(trans[trans.Length - 2], trans[trans.Length - 1], -width / 2, trans[trans.Length - 1]);
        Vector3 lc = GetPointsOnParalleLines(trans[trans.Length - 2], trans[trans.Length - 1], width / 2, trans[trans.Length - 1]);

        AddList(l_vertesx, lc, lb);
        ST(temp, P[trans.Length - 1], new string[] { "lc", "lb" }, lc, lb);

        float lr = Vector3.Distance(l_vertesx[l_vertesx.Count - 2], lastL);

        l_uv.Add(new Vector2((uvi + lr) / width, 1));
        l_uv.Add(new Vector2((uvi + lr) / width, 0));
        #endregion
        #endregion
        #region 三角形

        l_triangles = new List<int>() { 0, 1, 4, 0, 4, 3 };

        for (int i = 1; i < trans.Length - 1; i++)
        {
            for (int j = 0; j < 18; j++)
            {
                l_triangles.Add((i * 18 - 17) + 1 + j);
            }

            if (i < trans.Length - 2)//两个拐角连接点
            {
                l_triangles.Add(i * 18 + 1);
                l_triangles.Add(i * 18);
                l_triangles.Add(i * 18 + 4);

                l_triangles.Add(i * 18 + 1);
                l_triangles.Add(i * 18 + 4);
                l_triangles.Add(i * 18 + 3);
            }
        }

        l_triangles.Add(l_vertesx.Count - 2);
        l_triangles.Add(l_vertesx.Count - 1);
        l_triangles.Add(l_vertesx.Count - 4);

        l_triangles.Add(l_vertesx.Count - 1);
        l_triangles.Add(l_vertesx.Count - 3);
        l_triangles.Add(l_vertesx.Count - 4);
        #endregion


        Vector3[] normals = new Vector3[l_vertesx.Count];
        for (int i = 0; i < normals.Length; i++)
        {
            normals[i] = Vector3.up;
        }

        Mesh mesh = new Mesh();
        mesh.vertices = l_vertesx.ToArray();
        mesh.triangles = l_triangles.ToArray();
        mesh.normals = normals;
        mesh.uv = l_uv.ToArray();
        return mesh;
    }

    #region 核心
    /// <summary>求平行线上的点</summary>
    /// <param name="m"></param>
    /// <param name="n"></param>
    /// <param name="am"></param>
    /// <param name="origin"></param>
    /// <returns></returns>
    private static Vector3 GetPointsOnParalleLines(Vector3 m, Vector3 n, float am, Vector3 origin)
    {
        float mn = Vector3.Distance(n, m);
        float mo = n.x - m.x;
        float no = n.z - m.z;
        float ox = origin.x;
        float oy = origin.z;

        float ap = am * mo / mn;
        float pm = am * no / mn;
        return new Vector3(ox - pm, origin.y, ap + oy);
    }
    /// <summary>求相交点</summary>
    /// <param name="o1"></param>
    /// <param name="o2"></param>
    /// <param name="o3"></param>
    /// <param name="o4"></param>
    private static Vector3 GetLinesIntersection(Vector3 o1, Vector3 o2, Vector3 o3, Vector3 o4)
    {
        float x1 = o1.x;
        float x2 = o2.x;
        float x3 = o3.x;
        float x4 = o4.x;

        //float y1 = o1.y;
        //float y2 = o2.y;
        //float y3 = o3.y;
        //float y4 = o4.y;

        float z1 = o1.z;
        float z2 = o2.z;
        float z3 = o3.z;
        float z4 = o4.z;

        float x = (x1 * (z2 - z1) * (x4 - x3) - x3 * (z4 - z3) * (x2 - x1) + (z3 - z1) * (x4 - x3) * (x2 - x1)) / ((z2 - z1) * (x4 - x3) - (z4 - z3) * (x2 - x1));
        float y = 0;// (y1 * (x2 - x1) * (y4 - y3) - y3 * (x4 - x3) * (y2 - y1) + (x3 - x1) * (y4 - y3) * (y2 - y1)) / ((x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1));
        float z = (z1 * (x2 - x1) * (z4 - z3) - z3 * (x4 - x3) * (z2 - z1) + (x3 - x1) * (z4 - z3) * (z2 - z1)) / ((x2 - x1) * (z4 - z3) - (x4 - x3) * (z2 - z1));


        return new Vector3(x, y, z);
    }
    #endregion

    public static void AddList(List<int> lis, params int[] ins)
    {
        if (lis == null || ins == null) return;
        for (int i = 0; i < ins.Length; i++)
        {
            lis.Add(ins[i]);
        }
    }
    public static void AddList(List<Vector2> lvs, params Vector2[] vs)
    {
        if (lvs == null || vs == null)
        {
            return;
        }
        for (int i = 0; i < vs.Length; i++)
        {
            lvs.Add(vs[i]);
        }
    }
    public void AddList(List<Vector3> lvs, params Vector3[] vs)
    {
        if (lvs == null || vs == null) return;
        for (int i = 0; i < vs.Length; i++)
        {
            lvs.Add(vs[i]);
        }
    }
    public void ST(GameObject prefab, Transform pre, string[] n, params Vector3[] p)
    {
        for (int i = 0; i < p.Length; i++)
        {
            Vector3 item = p[i];

            GameObject game = GameObject.Instantiate(prefab, pre);
            game.name = n[i];

            game.transform.localPosition = item - pre.localPosition;
            game.SetActive(true);

        }
    }
    #endregion
}
